package org.koin.hos.scope;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.Lifecycle;
import ohos.aafwk.ability.LifecycleStateObserver;
import ohos.aafwk.content.Intent;
import org.koin.core.Koin;
import org.koin.core.component.KoinScopeComponent;
import org.koin.core.context.GlobalContext;
import org.koin.core.context.KoinContext;
import org.koin.core.error.NoScopeDefFoundException;
import org.koin.core.error.ScopeAlreadyCreatedException;
import org.koin.core.logger.Logger;
import org.koin.core.qualifier.TypeQualifier;
import org.koin.core.scope.Scope;

public class LifecycleScopeDelegate {

    private Scope _scope;
    private Ability ability;

    public LifecycleScopeDelegate(Ability ability,
                                  KoinContext koinContext,
                                  CreateScopeDelegate createScope) {

        Koin koin = koinContext.get();
        Logger logger = koin.getLogger();
        this.ability = ability;

        logger.debug("setup scope: " + _scope + " for " + ability);
        String scopeId = KoinScopeComponent.getScopeId(ability);
        _scope = koin.getScopeOrNull(scopeId);
        if (_scope == null && createScope != null) {
            _scope = createScope.invoke(koin);
        }
        logger.debug("got scope: " + _scope + " for " + ability);

        ability.getLifecycle().addObserver(new LifecycleStateObserver() {
            @Override
            public void onStateChanged(Lifecycle.Event event, Intent intent) {
                if (event == Lifecycle.Event.ON_STOP) {
                    logger.debug("Closing scope: " + _scope + " for " + ability);
                    if (_scope != null && !_scope.getClosed()) {
                        _scope.close();
                    }
                    _scope = null;
                }
            }
        });
    }

    public LifecycleScopeDelegate(Ability ability) {
        this(ability, GlobalContext.INSTANCE(), new CreateScopeDelegate() {
            @Override
            public Scope invoke(Koin koin) {
                String scopeId = KoinScopeComponent.getScopeId(ability);
                TypeQualifier scopeName = KoinScopeComponent.getScopeName(ability);
                try {
                    return koin.createScope(scopeId, scopeName);
                } catch (ScopeAlreadyCreatedException e) {
                    e.printStackTrace();
                } catch (NoScopeDefFoundException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }

    public Scope getValue() {
        if (_scope == null) {
            throw new IllegalStateException("can't get Scope for " + ability);
        }
        return _scope;
    }

    public interface CreateScopeDelegate {
        Scope invoke(Koin koin);
    }
}
